"""
知识库服务模块
整合文档处理和向量存储功能，提供完整的知识库管理接口
"""
import os
from typing import List, Dict, Any, Optional, Tuple
from langchain.schema import Document
from backend.document_processor import document_processor
from backend.chromadb_manager import chromadb_manager

class KnowledgeService:
    """
    知识库服务类
    提供文档管理、向量存储和检索功能的统一接口
    """
    
    def __init__(self):
        """
        初始化知识库服务
        使用默认的文档处理器和ChromaDB管理器
        """
        self.document_processor = document_processor
        self.db_manager = chromadb_manager
        # 用于跟踪文档哈希值的字典，键为文件路径，值为哈希值
        self.document_hashes = self._load_document_hashes()
    
    def _load_document_hashes(self) -> Dict[str, str]:
        """
        从数据库加载文档哈希信息
        
        Returns:
            文档哈希字典，键为文件路径，值为哈希值
        """
        document_hashes = {}
        try:
            # 查询数据库中所有文档，获取其哈希信息
            results = self.db_manager.vectorstore.get()
            # 安全地检查results和metadata键是否存在
            if results and isinstance(results, dict) and 'metadata' in results:
                metadata_list = results['metadata']
                # 确保metadata是列表类型并进行遍历
                if isinstance(metadata_list, list):
                    for metadata in metadata_list:
                        if isinstance(metadata, dict) and 'source' in metadata and 'content_hash' in metadata:
                            # 对于每个文件，只保留最新的哈希值
                            document_hashes[metadata['source']] = metadata['content_hash']
        except Exception as e:
            print(f"加载文档哈希信息时出错: {str(e)}")
        return document_hashes
    
    def _update_document_hashes(self, documents: List[Document]):
        """
        更新文档哈希信息
        
        Args:
            documents: 处理后的文档列表
        """
        for doc in documents:
            if 'source' in doc.metadata and 'content_hash' in doc.metadata:
                self.document_hashes[doc.metadata['source']] = doc.metadata['content_hash']
    
    def add_document(self, file_path: str, force_update: bool = False) -> Dict[str, Any]:
        """
        添加单个文档到知识库
        
        Args:
            file_path: 文档文件路径
            force_update: 是否强制更新，即使文档未变化
            
        Returns:
            处理结果，包含文档信息和添加的块数量
        """
        try:
            # 检查文件是否存在
            if not os.path.exists(file_path):
                return {
                    "success": False,
                    "message": f"文件不存在: {file_path}"
                }
            
            # 获取文件的现有哈希值（如果有）
            existing_hash = None if force_update else self.document_hashes.get(file_path)
            
            # 处理文档，启用更新检查
            documents = self.document_processor.process_document(
                file_path, 
                check_update=not force_update, 
                existing_hash=existing_hash
            )
            
            # 如果没有返回文档，说明文档未更新
            if not documents:
                return {
                    "success": True,
                    "message": "文档未更新，无需添加",
                    "filename": os.path.basename(file_path),
                    "chunks_added": 0
                }
            
            # 如果是更新现有文档，先删除旧文档
            if not force_update and file_path in self.document_hashes:
                delete_result = self.delete_documents_by_source(file_path)
                if not delete_result["success"]:
                    print(f"警告: 删除旧文档失败: {delete_result['message']}")
            
            # 添加到向量数据库
            document_ids = self.db_manager.add_documents(documents)
            
            if not document_ids:
                return {
                    "success": False,
                    "message": "添加文档到向量数据库失败"
                }
            
            # 更新文档哈希信息
            self._update_document_hashes(documents)
            
            # 返回成功结果
            return {
                "success": True,
                "message": "文档添加成功",
                "filename": os.path.basename(file_path),
                "chunks_added": len(document_ids),
                "document_ids": document_ids
            }
            
        except Exception as e:
            return {
                "success": False,
                "message": f"添加文档时出错: {str(e)}"
            }
    
    def add_documents_from_directory(self, directory_path: str, force_update: bool = False) -> Dict[str, Any]:
        """
        添加目录中的所有支持的文档到知识库
        
        Args:
            directory_path: 包含文档的目录路径
            force_update: 是否强制更新，即使文档未变化
            
        Returns:
            处理结果，包含添加的文档数量和块数量
        """
        try:
            # 检查目录是否存在
            if not os.path.exists(directory_path) or not os.path.isdir(directory_path):
                return {
                    "success": False,
                    "message": f"目录不存在或不是有效目录: {directory_path}"
                }
            
            # 处理目录中的所有文档，启用更新检查
            documents = self.document_processor.process_documents_in_directory(
                directory_path, 
                check_update=not force_update, 
                existing_hashes=None if force_update else self.document_hashes
            )
            
            # 如果没有返回文档，说明所有文档都未更新
            if not documents:
                return {
                    "success": True,
                    "message": "所有文档未更新，无需添加",
                    "source_files_count": 0,
                    "chunks_added": 0
                }
            
            # 收集需要删除的源文件路径
            sources_to_delete = set()
            if not force_update:
                for doc in documents:
                    if "source" in doc.metadata:
                        sources_to_delete.add(doc.metadata["source"])
            
            # 删除需要更新的旧文档
            for source_path in sources_to_delete:
                if source_path in self.document_hashes:
                    delete_result = self.delete_documents_by_source(source_path)
                    if not delete_result["success"]:
                        print(f"警告: 删除旧文档失败: {delete_result['message']}")
            
            # 添加到向量数据库
            document_ids = self.db_manager.add_documents(documents)
            
            if not document_ids:
                return {
                    "success": False,
                    "message": "添加文档到向量数据库失败"
                }
            
            # 更新文档哈希信息
            self._update_document_hashes(documents)
            
            # 统计不同源文件的数量
            source_files = set()
            for doc in documents:
                if "source" in doc.metadata:
                    source_files.add(doc.metadata["source"])
            
            # 返回成功结果
            return {
                "success": True,
                "message": "更新的文档添加成功",
                "source_files_count": len(source_files),
                "chunks_added": len(document_ids),
                "document_ids": document_ids[:10]  # 只返回前10个ID
            }
            
        except Exception as e:
            return {
                "success": False,
                "message": f"添加目录文档时出错: {str(e)}"
            }
    
    def add_text(self, text: str, metadata: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
        """
        添加文本内容到知识库
        
        Args:
            text: 文本内容
            metadata: 文本元数据
            
        Returns:
            处理结果
        """
        try:
            if not text or not text.strip():
                return {
                    "success": False,
                    "message": "文本内容不能为空"
                }
            
            # 分割文本
            documents = self.document_processor.split_text(text, metadata)
            
            if not documents:
                return {
                    "success": False,
                    "message": "文本分割失败"
                }
            
            # 添加到向量数据库
            document_ids = self.db_manager.add_documents(documents)
            
            if not document_ids:
                return {
                    "success": False,
                    "message": "添加文本到向量数据库失败"
                }
            
            # 返回成功结果
            return {
                "success": True,
                "message": "文本添加成功",
                "chunks_added": len(document_ids),
                "document_ids": document_ids
            }
            
        except Exception as e:
            return {
                "success": False,
                "message": f"添加文本时出错: {str(e)}"
            }
    
    def search_knowledge(self, query: str, k: int = 5, filter: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
        """
        在知识库中搜索相关文档
        
        Args:
            query: 搜索查询
            k: 返回的文档数量
            filter: 过滤条件
            
        Returns:
            搜索结果
        """
        try:
            if not query or not query.strip():
                return {
                    "success": False,
                    "message": "搜索查询不能为空"
                }
            
            # 执行搜索
            results = self.db_manager.search(query, k, filter)
            
            # 格式化搜索结果
            formatted_results = []
            for doc, score in results:
                # 计算相似度百分比
                try:
                    if isinstance(score, (int, float)):
                        # 重新使用欧氏距离的转换方式
                        # 由于欧氏距离值较大，需要调整转换系数以获得更合理的相似度百分比
                        similarity_percent = 100 / (1 + score * 0.1)  # 调整系数，使相似度显示更合理
                        
                        # 确保相似度在合理范围内
                        similarity_percent = max(0, min(100, similarity_percent))
                    else:
                        similarity_percent = 0.0
                except Exception as e:
                    # 如果计算出错，使用安全的默认值
                    similarity_percent = 0.0
                
                # 总是添加所有结果，不进行过滤
                formatted_results.append({
                    "content": doc.page_content,
                    "metadata": doc.metadata,
                    "similarity_score": float(similarity_percent)
                })
            
            # 根据相似度重新排序结果，确保最相关的内容排在前面
            formatted_results.sort(key=lambda x: x['similarity_score'], reverse=True)
            
            return {
                "success": True,
                "results": formatted_results,
                "total_results": len(formatted_results)
            }
            
        except Exception as e:
            return {
                "success": False,
                "message": f"搜索知识库时出错: {str(e)}"
            }
    
    def delete_document_by_id(self, document_id: str) -> Dict[str, Any]:
        """
        通过ID删除文档
        
        Args:
            document_id: 文档ID
            
        Returns:
            删除结果
        """
        try:
            if not document_id:
                return {
                    "success": False,
                    "message": "文档ID不能为空"
                }
            
            # 删除文档
            success = self.db_manager.delete_document(document_id)
            
            if success:
                return {
                    "success": True,
                    "message": "文档删除成功"
                }
            else:
                return {
                    "success": False,
                    "message": "文档删除失败，可能文档不存在"
                }
                
        except Exception as e:
            return {
                "success": False,
                "message": f"删除文档时出错: {str(e)}"
            }
    
    def delete_documents_by_source(self, source_path: str) -> Dict[str, Any]:
        """
        删除来自特定源的所有文档
        
        Args:
            source_path: 文档源路径
            
        Returns:
            删除结果
        """
        try:
            if not source_path:
                return {
                    "success": False,
                    "message": "源路径不能为空"
                }
            
            # 构建过滤条件
            filter = {"source": source_path}
            
            # 删除文档
            success = self.db_manager.delete_documents_by_filter(filter)
            
            if success:
                return {
                    "success": True,
                    "message": f"成功删除来自 {source_path} 的所有文档"
                }
            else:
                return {
                    "success": False,
                    "message": "删除文档失败"
                }
                
        except Exception as e:
            return {
                "success": False,
                "message": f"删除文档时出错: {str(e)}"
            }
    
    def get_knowledge_stats(self) -> Dict[str, Any]:
        """
        获取知识库统计信息
        
        Returns:
            知识库统计数据
        """
        try:
            # 获取文档数量
            document_count = self.db_manager.count_documents()
            
            return {
                "success": True,
                "document_count": document_count,
                "status": "active"
            }
            
        except Exception as e:
            return {
                "success": False,
                "message": f"获取知识库统计信息时出错: {str(e)}"
            }
    
    def clear_knowledge_base(self) -> Dict[str, Any]:
        """
        清空知识库中的所有文档
        
        Returns:
            操作结果
        """
        try:
            # 重置数据库
            success = self.db_manager.reset_database()
            
            if success:
                return {
                    "success": True,
                    "message": "知识库已清空"
                }
            else:
                return {
                    "success": False,
                    "message": "清空知识库失败"
                }
                
        except Exception as e:
            return {
                "success": False,
                "message": f"清空知识库时出错: {str(e)}"
            }

# 创建全局知识库服务实例
knowledge_service = KnowledgeService()